package com.gin.no_gay_alliance.app;

import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.room.Room;
import androidx.work.WorkManager;
import androidx.work.WorkRequest;

import com.bumptech.glide.Glide;
import com.gin.common.utils.TimeUtils;
import com.gin.nga.client.NgaClient;
import com.gin.no_gay_alliance.database.NgaDatabase;
import com.gin.no_gay_alliance.database.entity.NgaAccount;
import com.gin.no_gay_alliance.database.manager.AccountManager;
import com.gin.no_gay_alliance.database.migration.Migration1_2;
import com.gin.no_gay_alliance.database.migration.Migration2_3;
import com.gin.no_gay_alliance.database.migration.Migration3_4;
import com.gin.no_gay_alliance.database.migration.Migration4_5;
import com.gin.no_gay_alliance.database.migration.Migration5_6;
import com.gin.no_gay_alliance.interceptor.LoggingInterceptor;
import com.gin.no_gay_alliance.interceptor.ResourceNotFountInterceptor;
import com.gin.no_gay_alliance.manager.MissionManager;
import com.gin.no_gay_alliance.manager.PostManager;
import com.gin.no_gay_alliance.manager.provider.ResourceManager;
import com.gin.no_gay_alliance.manager.provider.ThirdPartyEmoteUrlProvider;
import com.gin.no_gay_alliance.utils.BbsCodeUtils;
import com.gin.no_gay_alliance.utils.DataStoreUtils;
import com.gin.no_gay_alliance.utils.ImageUtils;
import com.gin.no_gay_alliance.utils.MyHandler;
import com.gin.no_gay_alliance.worker.CheckInWorker;
import com.gin.no_gay_alliance.worker.ScanTaskWorker;
import com.gin.no_gay_alliance.worker.UpdateNoticeWorker;
import com.gin.no_gay_alliance.worker.WatchingWorker;
import com.wgw.photo.preview.PhotoPreview;

import java.io.File;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.OkHttpClient;

/**
 * app
 *
 * @author : ginstone
 * @version : v1.0.0
 * @since : 2023/8/1 17:18
 **/
public class MyApplication extends Application implements MyHandler.Callback {
    public static final String TAG = MyApplication.class.getSimpleName();
    /**
     * 清理Glide缓存的日期(每天执行一次)
     */
    private final static String DATA_STORE_KEY_CLEAR_CACHE_DATE = "CLEAR_CACHE_DATE";
    /**
     * dpi
     */
    public static int DEVICE_DENSITY_DPI;

    public static MyApplication app;
    public NgaDatabase ngaDatabase;
    public AccountManager accountManager;
    public OkHttpClient okHttpClient;
    public ManagerFactory managerFactory;
    public MyHandler handler;
    public ThreadPoolExecutor threadPoolExecutor;

    @Override
    public void onCreate() {
        super.onCreate();
        app = this;
        handler = new MyHandler(this, this);

        threadPoolExecutor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(100));

        ngaDatabase = Room.databaseBuilder(this, NgaDatabase.class, "nga_database")
                .addMigrations(new Migration1_2())
                .addMigrations(new Migration2_3())
                .addMigrations(new Migration3_4())
                .addMigrations(new Migration4_5())
                .addMigrations(new Migration5_6())
                .allowMainThreadQueries()
                .build();
        // 初始化 okhttp客户端
        File cacheDir = new File(getCacheDir(), "okhttp");
        okHttpClient = new OkHttpClient.Builder()
                .cache(new Cache(cacheDir, 1024 * 1024 * 200))
                .addInterceptor(new ResourceNotFountInterceptor())
                .addInterceptor(new LoggingInterceptor())
                .readTimeout(30, TimeUnit.SECONDS)
                .callTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS)
                .build();

        // 账号管理器初始化
        this.accountManager = new AccountManager(ngaDatabase.ngaAccountDao(), okHttpClient);
        // 管理器工厂初始化
        this.managerFactory = new ManagerFactory();

        // 加载第三方表情
        ThirdPartyEmoteUrlProvider.requestThirdPartyEmoteCategories(d -> {
        });
        // 加载CommonUi数据
        ResourceManager.commonUiProvider().async(false, d -> {
        });
        // 加载BbsCodeCore数据
        ResourceManager.bbsCodeCoreProvider().async(false, d -> {
            //写入静态变量，用于替换表情代码
            BbsCodeUtils.EMOTE_GROUPS = d.getEmoteGroups();
        });
        // 加载首页信息
        ResourceManager.bbsIndexProvider().async(false, d -> {
        });


        // dpi
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(metrics);
        DEVICE_DENSITY_DPI = metrics.densityDpi;

        // 请求屏蔽数据
        managerFactory.getBlockDataManager().blockDataList(false, d -> {
        });
        //每天执行一次清理部分缓存任务
        dailyClear();
        //自动签到
        autoCheckInWorker();
        // 当前版本号
        Log.d(TAG, "APP当前版本: " + getVersionName());
        // 为图片预览框架配置全局图片加载器
        PhotoPreview.setGlobalImageLoader((position, source, imageView) -> {
            if (source instanceof ImageUtils.PreviewSource) {
                Glide.with(imageView.getContext()).load(((ImageUtils.PreviewSource) source).getPreviewUrl()).into(imageView);
            }
            if (source instanceof String) {
                Glide.with(imageView.getContext()).load(String.valueOf(source)).into(imageView);
            }
        });

        // 启动自动扫描
        ScanTaskWorker.startWorker();
        // 启动监控
        WorkManager.getInstance(this).cancelAllWorkByTag(WatchingWorker.class.getName());
        WatchingWorker.startWorker();
        // 启动提醒消息更新
        UpdateNoticeWorker.startWorker(0);
    }

    public File getDataDir(String dirName) {
        return new File(getDataDir(), dirName);
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        return false;
    }

    /**
     * 自动签到
     */
    private void autoCheckInWorker() {
        // 所有账号
        List<NgaAccount> ngaAccounts = ngaDatabase.ngaAccountDao().listAll();
        // 任务管理器
        MissionManager missionManager = managerFactory.getMissionManager();
        // 自动签到名单
        Set<Long> autoCheckInUsers = missionManager.getAutoCheckInUsers();
        for (NgaAccount ngaAccount : ngaAccounts) {
            // 如果在名单内，提交自动签到工作
            if (autoCheckInUsers.contains(ngaAccount.userId)) {
                Log.d(TAG, "提交自动签到工作: " + ngaAccount.username);
                WorkRequest workRequest = CheckInWorker.buildWorkRequest(ngaAccount.cookie);
                WorkManager.getInstance(this).enqueue(workRequest);
            }
        }
    }


    /**
     * 每天执行一次清理部分缓存任务
     */
    private void dailyClear() {
        // 每天执行一次清理部分缓存任务
        DataStoreUtils instance = DataStoreUtils.getInstance();
        String today = TimeUtils.format(ZonedDateTime.now(), TimeUtils.DATE_FORMATTER);
        String date = instance.get(DATA_STORE_KEY_CLEAR_CACHE_DATE, "");
        if (!today.equals(date)) {
            // 清理Glide 缓存
            ImageUtils.clearGlideCache(this);
            // 清理发帖暂存数据
            DataStoreUtils.getInstance(PostManager.DATA_STORE_NAME).clear();
        }
        instance.set(DATA_STORE_KEY_CLEAR_CACHE_DATE, today);
    }

    /**
     * 将dpi转换为px
     *
     * @param dpi dpi
     * @return px
     */
    public static int dip2px(int dpi) {
        return (int) (dpi * MyApplication.DEVICE_DENSITY_DPI / 160f);
    }

    public static NgaClient getClient() {
        return app.accountManager.getClient();
    }

    /**
     * 获取APP当前版本号
     *
     * @return APP当前版本号
     */
    public static String getVersionName() {
        return app.getPackageInfo().versionName;
    }

    /**
     * 获取包信息
     *
     * @return {@link PackageInfo}
     */
    public PackageInfo getPackageInfo() {
        try {
            return app.getPackageManager().getPackageInfo(app.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
}
